boycot 搜索
avatar

boycot

Github Webhooks与Koa2实现简单的前端自动化部署

前言

因为博客使用 Gatsbyjs 进行搭建,Markdown 文章写完之后会打包成静态 HTML 文件,文章是存在项目文件中并非数据库中,所以每次进行博客文章更新后,都需要重新进行打包构建。在进行 git push 后,我需要连到云服务器中,然后进入项目目录,执行 git pull / npm run clean / npm run build 等命令。

为了简化该操作,通过使用 Github 的 Webhooks 服务,在服务端监听 git push 事件,然后自动执行编写好的脚本从而实现自动化构建部署。以后 Git push 后就无需再进行后续操作,由脚本完成。

目前主流的自动化构建部署工具可以选择 Jenkins,Jenkins 是一个持续集成管理平台,提供超过 1000 个插件来支持构建、部署、自动化, 满足任何项目的需要。但由于 Jenkins 是基于Java环境,而且功能过于强大,对于个人的项目来说有点大材小用,而且加重个人服务器资源的压力。所以没有采用 Jenkins 进行自动化构建部署,而是采用自己编写的Koa2服务来接收 Github Webhook 来实现简单自动化构建。

配置 Webhooks

  1. 进入自己需要监听 Push 请求的 Github 仓库,点击 Settings => Webhooks => Add webhook Create Webhook
  2. 填写自己服务器请求地址,配置 Secret(用于后面的 Sha1 解码验证),并选择要监听的事件,本次只监听 push Webhook form
  3. 进入到对应 Webhooks 详情,下方可以查看到每个请求记录,点击 Redeliver 可以重新发送该请求。 Redeliver

后端 Koa2 服务

后端的 Koa2 服务是本功能的最重要的环节。其处理流程:

  1. 接收 Github Webhooks 的 Post 请求
  2. 提取请求头与请求 Body 信息,并验证是否缺少必要参数
  3. 使用 Crypto 的 HMACSHA1 算法,将服务端设置的密钥对请求 Body 进行哈希编码,然后判断解码出来的与请求头中的 x-hub-signature 是否匹配,防止有他人对自己的服务器发送了伪造的非法请求或篡改了 Github 原请求。
  4. 针对不同 Git 事件与 Git 仓库使用 Nodejs 的 child_process 执行不同的脚本文件
const Router = require("koa-router");
const Response = require("../utils/response");
const crypto = require("crypto");
const { exec } = require("child_process");

const logger = require("../utils/log");
const { webhookSecret } = require("../config/config");

const r = new Response();
const router = new Router();

// router的路由路径在Github配置webhook时配置,webhook为向该路径发送请求
router.post("/****", async (ctx) => {
  const requestData = ctx.request.body;
  const sig = ctx.headers["x-hub-signature"];
  const event = ctx.headers["x-github-event"];
  const id = ctx.headers["x-github-delivery"];
  if (!sig || !event || !id) {
    ctx.body = r.error(310, "No Github hook headers");
    return;
  }
  if (!["ping", "push"].includes(event)) {
    ctx.body = r.error(311, "Gihub Hook events not allow");
    return;
  }
  const { repository, sender } = requestData;
  if (!repository || !sender) {
    ctx.body = r.error(312, "Missing essential parameters");
    return;
  }
  const { name: repositoryName } = repository;
  logger("接收到Webhook", 1, `event:${event}, respository: ${repositoryName}`);
  const clientSig = `sha1=${crypto
    .createHmac("sha1", webhookSecret)
    .update(JSON.stringify(requestData))
    .digest("hex")}`;
  if (sig !== clientSig) {
    logger("Webhook X-Hub-Signature解码", 0, "解码不匹配");
    ctx.body = r.error(313, "X-Hub-Signature does not match");
    return;
  }
  if (event === "ping") {
    ctx.body = {
      errCode: 200,
      errMsg: "Success",
    };
  } else if (event === "push") {
    ctx.body = {
      errCode: 200,
      errMsg: "Success",
    };
    if (repositoryName === "****") {
      updateBlog();
    }
  }
});

// updateBlog为接收到hook后要执行的操作
const updateBlog = () => {
  exec("****.bat", (err) => {
    if (err) {
      logger("执行****.bat", 0, err);
      return;
    }
    logger("执行****.bat", 1);
  });
};

module.exports = {
  githubWebhookRouter: router,
};

在新建 Webhooks 后,github 会发送一个 ping 事件到目标服务器,所以这里加多了一种 ping 事件的处理(直接返回 200)。

本次我设置了只有 push 事件会发请求,所以只处理了 push 事件,如果设置 Webhooks 监听其他事件,例如 release、issues、star 等,可自行扩展对应功能。

其他说明

  1. 后端可直接使用原生 Nodejs 搭建服务,使用 github-webhook-hanlder 包可快速搭建
  2. 建议设置 Secert 密钥,防止伪造的请求
  3. 本方式适合简单的前端资源自动化部署构建,对于大型的项目还是建议使用 Jenkins 等持续集成工具进行自动化部署
  4. 可监听 Github Webhooks 其他事件,issue、start 等,并通过 Github API 可实现下 Git 仓库机器人等功能
  5. Github Webhooks 请求中有很多有用的信息,例如多人项目中你可以记录是由谁 push 的,或者处理的是哪个分支等,都可以提取出来进行不同的处理。
  6. 脚本可使用 Shell 编写再由 Nodejs 的 child_process 去执行,也可以直接编写 nodejs 命令直接去执行文件操作。社区也提供很多类似shelljsexec-sh等 NPM 包可以更优雅的编写脚本命令。
  7. 这种方式适合将网站自动部署到自己的个人服务器,如果没有服务器可以采用Github Page方式部署,这时候可以利用Github Action去实现,具体后面再写一篇文章说明。

以上内容未经授权请勿随意转载。

乳白
杏仁黄
茉莉黄
麦秆黄
油菜花黄
佛手黄
篾黄
葵扇黄
柠檬黄
金瓜黄
藤黄
酪黄
香水玫瑰黄
淡密黄
大豆黄
素馨黄
向日葵黄
雅梨黄
黄连黄
金盏黄
蛋壳黄
肉色
鹅掌黄
鸡蛋黄
鼬黄
榴萼黄
淡橘橙
枇杷黄
橙皮黄
北瓜黄
杏黄
雄黄
万寿菊黄
菊蕾白
秋葵黄
硫华黄
柚黄
芒果黄
蒿黄
姜黄
香蕉黄
草黄
新禾绿
月灰
淡灰绿
草灰绿
苔绿
碧螺春绿
燕羽灰
蟹壳灰
潭水绿
橄榄绿
蚌肉白
豆汁黄
淡茧黄
乳鸭黄
荔肉白
象牙黄
炒米黄
鹦鹉冠黄
木瓜黄
浅烙黄
莲子白
谷黄
栀子黄
芥黄
银鼠灰
尘灰
枯绿
鲛青
粽叶绿
灰绿
鹤灰
淡松烟
暗海水绿
棕榈绿
米色
淡肉色
麦芽糖黄
琥珀黄
甘草黄
初熟杏黄
浅驼色
沙石黄
虎皮黄
土黄
百灵鸟灰
山鸡黄
龟背黄
苍黄
莱阳梨黄
蜴蜊绿
松鼠灰
橄榄灰
蟹壳绿
古铜绿
焦茶绿
粉白
落英淡粉
瓜瓤粉
蜜黄
金叶黄
金莺黄
鹿角棕
凋叶棕
玳瑁黄
软木黄
风帆黄
桂皮淡棕
猴毛灰
山鸡褐
驼色
茶褐
古铜褐
荷花白
玫瑰粉
橘橙
美人焦橙
润红
淡桃红
海螺橙
桃红
颊红
淡罂粟红
晨曦红
蟹壳红
金莲花橙
草莓红
龙睛鱼红
蜻蜓红
大红
柿红
榴花红
银朱
朱红
鲑鱼红
金黄
鹿皮褐
醉瓜肉
麂棕
淡银灰
淡赭
槟榔综
银灰
海鸥灰
淡咖啡
岩石棕
芒果棕
石板灰
珠母灰
丁香棕
咖啡
筍皮棕
燕颔红
玉粉红
金驼
铁棕
蛛网灰
淡可可棕
中红灰
淡土黄
淡豆沙
椰壳棕
淡铁灰
中灰驼
淡栗棕
可可棕
柞叶棕
野蔷薇红
菠萝红
藕荷
陶瓷红
晓灰
余烬红
火砖红
火泥棕
绀红
橡树棕
海报灰
玫瑰灰
火山棕
豆沙
淡米粉
初桃粉红
介壳淡粉红
淡藏花红
瓜瓤红
芙蓉红
莓酱红
法螺红
落霞红
淡玫瑰灰
蟹蝥红
火岩棕
赭石
暗驼棕
酱棕
栗棕
洋水仙红
谷鞘红
苹果红
铁水红
桂红
极光红
粉红
舌红
曲红
红汞红
淡绯
无花果红
榴子红
胭脂红
合欢红
春梅红
香叶红
珊瑚红
萝卜红
淡茜红
艳红
淡菽红
鱼鳃红
樱桃红
淡蕊香红
石竹红
草茉莉红
茶花红
枸枢红
秋海棠红
丽春红
夕阳红
鹤顶红
鹅血石红
覆盆子红
貂紫
暗玉紫
栗紫
葡萄酱紫
牡丹粉红
山茶红
海棠红
玉红
高粱红
满江红
枣红
葡萄紫
酱紫
淡曙红
唐菖蒲红
鹅冠红
莓红
枫叶红
苋菜红
烟红
暗紫苑红
殷红
猪肝紫
金鱼紫
草珠红
淡绛红
品红
凤仙花红
粉团花红
夹竹桃红
榲桲红
姜红
莲瓣红
水红
报春红
月季红
豇豆红
霞光红
松叶牡丹红
喜蛋红
鼠鼻红
尖晶玉红
山黎豆红
锦葵红
鼠背灰
甘蔗紫
石竹紫
苍蝇灰
卵石紫
李紫
茄皮紫
吊钟花红
兔眼红
紫荆红
菜头紫
鹞冠紫
葡萄酒红
磨石紫
檀紫
火鹅紫
墨紫
晶红
扁豆花红
白芨红
嫩菱红
菠根红
酢酱草红
洋葱紫
海象紫
绀紫
古铜紫
石蕊红
芍药耕红
藏花红
初荷红
马鞭草紫
丁香淡紫
丹紫红
玫瑰红
淡牵牛紫
凤信紫
萝兰紫
玫瑰紫
藤萝紫
槿紫
蕈紫
桔梗紫
魏紫
芝兰紫
菱锰红
龙须红
蓟粉红
电气石红
樱草紫
芦穗灰
隐红灰
苋菜紫
芦灰
暮云灰
斑鸠灰
淡藤萝紫
淡青紫
青蛤壳紫
豆蔻紫
扁豆紫
芥花紫
青莲
芓紫
葛巾紫
牵牛紫
紫灰
龙睛鱼紫
荸荠紫
古鼎灰
乌梅紫
深牵牛紫
银白
芡食白
远山紫
淡蓝紫
山梗紫
螺甸紫
玛瑙灰
野菊紫
满天星紫
锌灰
野葡萄紫
剑锋紫
龙葵紫
暗龙胆紫
晶石紫
暗蓝紫
景泰蓝
尼罗蓝
远天蓝
星蓝
羽扇豆蓝
花青
睛蓝
虹蓝
湖水蓝
秋波蓝
涧石蓝
潮蓝
群青
霁青
碧青
宝石蓝
天蓝
柏林蓝
海青
钴蓝
鸢尾蓝
牵牛花蓝
飞燕草蓝
品蓝
银鱼白
安安蓝
鱼尾灰
鲸鱼灰
海参灰
沙鱼灰
钢蓝
云水蓝
晴山蓝
靛青
大理石灰
海涛蓝
蝶翅蓝
海军蓝
水牛灰
牛角灰
燕颔蓝
云峰白
井天蓝
云山蓝
釉蓝
鸥蓝
搪磁蓝
月影白
星灰
淡蓝灰
鷃蓝
嫩灰
战舰灰
瓦罐灰
青灰
鸽蓝
钢青
暗蓝
月白
海天蓝
清水蓝
瀑布蓝
蔚蓝
孔雀蓝
甸子蓝
石绿
竹篁绿
粉绿
美蝶绿
毛绿
蔻梢绿
麦苗绿
蛙绿
铜绿
竹绿
蓝绿
穹灰
翠蓝
胆矾蓝
樫鸟蓝
闪蓝
冰山蓝
虾壳青
晚波蓝
蜻蜓蓝
玉鈫蓝
垩灰
夏云灰
苍蓝
黄昏灰
灰蓝
深灰蓝
玉簪绿
青矾绿
草原远绿
梧枝绿
浪花绿
海王绿
亚丁绿
镍灰
明灰
淡绿灰
飞泉绿
狼烟灰
绿灰
苍绿
深海绿
长石灰
苷蓝绿
莽丛绿
淡翠绿
明绿
田园绿
翠绿
淡绿
葱绿
孔雀绿
艾绿
蟾绿
宫殿绿
松霜绿
蛋白石绿
薄荷绿
瓦松绿
荷叶绿
田螺绿
白屈菜绿
河豚灰
蒽油绿
槲寄生绿
云杉绿
嫩菊绿
艾背绿
嘉陵水绿
玉髓绿
鲜绿
宝石绿
海沬绿
姚黄
橄榄石绿
水绿
芦苇绿
槐花黄绿
苹果绿
芽绿
蝶黄
橄榄黄绿
鹦鹉绿
油绿
象牙白
汉白玉
雪白
鱼肚白
珍珠灰
浅灰
铅灰
中灰
瓦灰
夜灰
雁灰
深灰